<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <h2>一、什么是SPA</h2>
  <div>SPA（single-page application），翻译过来就是单页应用</div>
  <div>在单页应用中，所有必要的代码（HTML、JavaScript和CSS）都通过单个页面的加载而检索，或者根据需要（通常是为响应用户操作）动态装载适当的资源并添加到页面
    页面在任何时间点都不会重新加载，也不会将控制转移到其他页面</div>
  <h2>二、SPA和MPA的区别</h2>
  <div>MPA（MultiPage-page application），翻译过来就是多页应用。在MPA中，每个页面都是一个主页面，都是独立的</div>
  <br>
  <div>单页面应用（SPA）</div>
  <ul>
    <li>一个主页面和多个页面片段</li>
    <li>局部刷新</li>
    <li>哈希模式</li>
    <li>难实现SEO，可使用SSR方式改善</li>
    <li>数据传递容易</li>
    <li>页面切换快，用户体验好</li>
    <li>维护相对容易</li>
  </ul>
  <div>多页面应用（MPA）</div>
  <ul>
    <li>多个主页面</li>
    <li>整页刷新</li>
    <li>历史模式</li>
    <li>SEO容易实现</li>
    <li>通过url、cookie、localStorage等传递</li>
    <li>切换加载资源，速度慢，用户体验差</li>
    <li>维护成本相对复杂</li>
  </ul>
  <h2>三、实现一个SPA</h2>
  <div>原理</div>
  <ul>
    <li>监听地址栏中hash变化驱动界面变化</li>
    <li>用pushsate记录浏览器的历史，驱动界面发送变化</li>
  </ul>
  <div>实现</div>
  <br>
  <div>hash 模式</div>
  <div>核心通过监听url中的hash来进行路由跳转</div>
  <script>
    // 定义 Router
    // class Router {
    //     constructor () {
    //         this.routes = {}; // 存放路由path及callback
    //         this.currentUrl = '';
            
    //         // 监听路由change调用相对应的路由回调
    //         window.addEventListener('load', this.refresh, false);
    //         window.addEventListener('hashchange', this.refresh, false);
    //     }
        
    //     route(path, callback){
    //         this.routes[path] = callback;
    //     }
        
    //     push(path) {
    //         this.routes[path] && this.routes[path]()
    //     }
    // }

    // // 使用 router
    // window.miniRouter = new Router();
    // miniRouter.route('/', () => console.log('page1'))
    // miniRouter.route('/page2', () => console.log('page2'))

    // miniRouter.push('/') // page1
    // miniRouter.push('/page2') // page2
  </script>
  <br>
  <div>history模式</div>
  <div>history 模式核心借用 HTML5 history api，api 提供了丰富的 router 相关属性</div>
  <br>
  <div>先了解一个几个相关的api</div>
  <ul>
    <li>history.pushState 浏览器历史纪录添加记录</li>
    <li>history.replaceState修改浏览器历史纪录中当前纪录</li>
    <li>history.popState 当 history 发生变化时触发</li>
  </ul>
  <script>
    // 定义 Router
    // class Router {
    //     constructor () {
    //         this.routes = {};
    //         this.listerPopState()
    //     }
        
    //     init(path) {
    //         history.replaceState({path: path}, null, path);
    //         this.routes[path] && this.routes[path]();
    //     }
        
    //     route(path, callback){
    //         this.routes[path] = callback;
    //     }
        
    //     push(path) {
    //         history.pushState({path: path}, null, path);
    //         this.routes[path] && this.routes[path]();
    //     }
        
    //     listerPopState () {
    //         window.addEventListener('popstate' , e => {
    //             const path = e.state && e.state.path;
    //             this.routers[path] && this.routers[path]()
    //         })
    //     }
    // }

    // // 使用 Router

    // window.miniRouter = new Router();
    // miniRouter.route('/', ()=> console.log('page1'))
    // miniRouter.route('/page2', ()=> console.log('page2'))

    // // 跳转
    // miniRouter.push('/page2')  // page2
  </script>
  <h2>四、题外话：如何给SPA做SEO</h2>
  <div>下面给出基于Vue的SPA如何实现SEO的三种方式</div>
  <ul>
    <li>SSR服务端渲染:将组件或页面通过服务器生成html，再返回给浏览器，如nuxt.js</li>
    <li>静态化</li>
    <li>用Phantomjs针对爬虫处理</li>
  </ul>
</body>
</html>